// lib/src/services/shipment_service.dart

import '../models/shipment.dart';
import 'storage_service.dart';
import 'auth_service.dart';
import 'logging_service.dart';
import 'package:intl/intl.dart';

/// 运单服务，负责处理运单相关的业务逻辑。
class ShipmentService {
  final StorageService _storageService;
  final AuthService _authService;
  final LoggingService _loggingService;

  ShipmentService(
    this._storageService,
    this._authService,
    this._loggingService,
  );

  // 英文状态键常量，用于内部逻辑和与模型的交互
  static const String statusNotShipped = "Not Shipped";
  static const String statusShipped = "Shipped";
  static const String statusArrived = "Arrived";
  static const String statusPickedUp = "Picked Up";

  // 英文运输方式键常量
  static const String transportSea = "Sea";
  static const String transportAir = "Air";

  Future<Shipment?> addNewShipment({
    required String customerCode,
    required String cargoShortName,
    required int packageCount,
    required int departurePortTimezoneOffsetHours,
    required String
    transportMode, // 期望传入的是英文键, e.g., ShipmentService.transportSea
    required int estimatedTransitDays,
    required String cargoDetails,
  }) async {
    final traderUsername =
        _authService.currentTraderUsername ?? "UnknownTrader";
    if (_authService.currentRole != UserRole.trader) {
      _loggingService.warning(
        'Permission denied: Attempt to add shipment by non-trader. Current role: ${_authService.currentRole}',
      );
      print('Permission error: Only traders can add new shipments.');
      return null;
    }
    if (_storageService.getCustomerByCode(customerCode) == null) {
      _loggingService.warning(
        'Add shipment failed for trader "$traderUsername": Customer code "$customerCode" does not exist.',
      );
      print(
        'Error: Customer code "$customerCode" does not exist. Cannot create shipment for this customer.',
      );
      return null;
    }
    if (cargoShortName.length > 16 || cargoShortName.isEmpty) {
      _loggingService.warning(
        'Add shipment failed for trader "$traderUsername": Invalid cargo short name "$cargoShortName".',
      );
      print('Error: Cargo short name must be between 1 and 16 characters.');
      return null;
    }
    // 验证 transportMode 是否是已知的英文键
    if (transportMode != transportSea && transportMode != transportAir) {
      _loggingService.warning(
        'Add shipment failed for trader "$traderUsername": Invalid transport mode "$transportMode".',
      );
      print(
        'Error: Invalid transport mode "$transportMode". Valid modes are: $transportSea, $transportAir',
      );
      return null;
    }

    final newShipment = Shipment(
      customerCode: customerCode,
      cargoShortName: cargoShortName,
      packageCount: packageCount,
      departurePortTimezoneOffsetHours: departurePortTimezoneOffsetHours,
      transportMode: transportMode, // 存储英文键
      estimatedTransitDays: estimatedTransitDays,
      cargoDetails: cargoDetails,
      status: statusNotShipped, // 新运单默认为 "Not Shipped"
    );
    await _storageService.addShipment(newShipment);
    _loggingService.info(
      'Trader "$traderUsername" added new shipment ${newShipment.trackingNumber} for customer "$customerCode".',
    );
    return newShipment;
  }

  /// 更新运单状态。
  /// newStatusEnglishKey 应该是来自 ShipmentService 的状态常量之一，如 ShipmentService.statusShipped。
  Future<Shipment?> updateShipmentStatus(
    String trackingNumber,
    String newStatusEnglishKey, // 期望是英文键, e.g., ShipmentService.statusShipped
  ) async {
    final traderUsername =
        _authService.currentTraderUsername ?? "UnknownTrader";
    if (_authService.currentRole != UserRole.trader) {
      _loggingService.warning(
        'Permission denied: Attempt to update shipment status by non-trader. Tracking: $trackingNumber',
      );
      print('Permission error: Only traders can update shipment status.');
      return null;
    }
    final shipment = _storageService.getShipmentByTrackingNumber(
      trackingNumber,
    );
    if (shipment == null) {
      _loggingService.warning(
        'Update shipment status failed for trader "$traderUsername": Shipment "$trackingNumber" not found.',
      );
      print(
        'Error: Shipment with tracking number "$trackingNumber" not found.',
      );
      return null;
    }

    const validStatuses = [
      statusNotShipped,
      statusShipped,
      statusArrived,
      statusPickedUp,
    ];
    if (!validStatuses.contains(newStatusEnglishKey)) {
      _loggingService.warning(
        'Update shipment status failed for trader "$traderUsername", shipment "$trackingNumber": Invalid status "$newStatusEnglishKey".',
      );
      print(
        'Error: Invalid shipment status "$newStatusEnglishKey". Valid statuses are: ${validStatuses.join(", ")}',
      );
      return null;
    }

    // 状态转换逻辑
    if (newStatusEnglishKey == statusArrived) {
      if (shipment.shippedDateUtc != null &&
          DateTime.now().toUtc().isBefore(shipment.shippedDateUtc!)) {
        final shippedDateFormatted = DateFormat(
          'yyyy-MM-dd',
        ).format(shipment.shippedDateUtc!);
        print(
          'Error: Cargo cannot be marked as "Arrived" before shipment. Shipped date ($shippedDateFormatted) is later than current time. Please update shipped date or set actual arrival date manually.',
        );
        return null;
      }
    }

    // 根据新状态重置相关日期
    if (newStatusEnglishKey == statusShipped) {
      shipment.actualArrivalDateUtc = null; // 如果重新标记为已发货，则清除到达和提货日期
      shipment.pickupDateUtc = null;
    } else if (newStatusEnglishKey == statusNotShipped) {
      shipment.shippedDateUtc = null;
      shipment.estimatedArrivalDateUtc = null;
      shipment.actualArrivalDateUtc = null;
      shipment.pickupDateUtc = null;
    }

    final oldStatus = shipment.status; // 记录旧状态用于日志
    shipment.updateStatus(newStatusEnglishKey);
    final success = await _storageService.updateShipment(shipment);

    if (success) {
      _loggingService.info(
        'Trader "$traderUsername" updated shipment "$trackingNumber" status from "$oldStatus" to "$newStatusEnglishKey".',
      );
      return shipment;
    } else {
      _loggingService.error(
        'Failed to save shipment "$trackingNumber" status update for trader "$traderUsername".',
      );
      print('Error: Failed to save shipment $trackingNumber status update.');
      return null;
    }
  }

  Future<Shipment?> _findShipmentForUpdate(String trackingNumber) async {
    if (_authService.currentRole != UserRole.trader) {
      print('Permission error: Only traders can update shipment information.');
      return null;
    }
    final shipment = _storageService.getShipmentByTrackingNumber(
      trackingNumber,
    );
    if (shipment == null) {
      print(
        'Error: Shipment with tracking number "$trackingNumber" not found.',
      );
      return null;
    }
    return shipment;
  }

  Future<Shipment?> setShippedDate(
    String trackingNumber,
    DateTime shippedDateUtc,
  ) async {
    final shipment = await _findShipmentForUpdate(trackingNumber);
    if (shipment == null) return null;

    final createdTimeSecondPrecision = DateTime.utc(
      shipment.createdTimeUtc.year,
      shipment.createdTimeUtc.month,
      shipment.createdTimeUtc.day,
      shipment.createdTimeUtc.hour,
      shipment.createdTimeUtc.minute,
      shipment.createdTimeUtc.second,
    );
    final shippedDateDayPrecision = DateTime.utc(
      shippedDateUtc.year,
      shippedDateUtc.month,
      shippedDateUtc.day,
    );

    if (shippedDateDayPrecision.isBefore(
      createdTimeSecondPrecision.subtract(Duration(days: 1)),
    )) {
      final createdTimeFormatted = DateFormat(
        'yyyy-MM-dd',
      ).format(shipment.createdTimeUtc);
      print(
        'Error: Shipped date cannot be earlier than shipment creation date ($createdTimeFormatted).',
      );
      return null;
    }

    shipment.shippedDateUtc = shippedDateUtc;
    shipment.estimatedArrivalDateUtc = shippedDateUtc.add(
      Duration(days: shipment.estimatedTransitDays),
    );

    // 如果当前状态是 "Not Shipped"，则自动更新为 "Shipped"
    if (shipment.status == statusNotShipped) {
      shipment.status = statusShipped;
    }

    final success = await _storageService.updateShipment(shipment);
    if (success) {
      return shipment;
    } else {
      print(
        'Error: Failed to save shipment $trackingNumber shipped date update.',
      );
      return null;
    }
  }

  Future<Shipment?> setArrivalDate(
    String trackingNumber,
    DateTime arrivalDateUtc,
  ) async {
    final shipment = await _findShipmentForUpdate(trackingNumber);
    if (shipment == null) return null;

    if (shipment.shippedDateUtc != null &&
        arrivalDateUtc.isBefore(shipment.shippedDateUtc!)) {
      final shippedDateFormatted = DateFormat(
        'yyyy-MM-dd',
      ).format(shipment.shippedDateUtc!);
      print(
        'Error: Actual arrival date cannot be earlier than shipped date ($shippedDateFormatted).',
      );
      return null;
    }
    if (shipment.shippedDateUtc == null) {
      print(
        'Warning: Setting actual arrival date for a shipment that has not been marked as shipped yet. Ensure shipped date is also updated.',
      );
    }

    shipment.actualArrivalDateUtc = arrivalDateUtc;
    // 如果状态是 "Shipped" 或 "Not Shipped"，则更新为 "Arrived"
    if (shipment.status == statusShipped ||
        shipment.status == statusNotShipped) {
      shipment.status = statusArrived;
    }

    final success = await _storageService.updateShipment(shipment);
    if (success) {
      return shipment;
    } else {
      print(
        'Error: Failed to save shipment $trackingNumber arrival date update.',
      );
      return null;
    }
  }

  Future<Shipment?> setPickupDate(
    String trackingNumber,
    DateTime pickupDateUtc,
  ) async {
    final shipment = await _findShipmentForUpdate(trackingNumber);
    if (shipment == null) return null;

    if (shipment.actualArrivalDateUtc == null) {
      print(
        'Error: Actual arrival date must be set before setting pickup date.',
      );
      return null;
    }

    if (pickupDateUtc.isBefore(shipment.actualArrivalDateUtc!)) {
      final arrivalDateFormatted = DateFormat(
        'yyyy-MM-dd',
      ).format(shipment.actualArrivalDateUtc!);
      print(
        'Error: Pickup date cannot be earlier than actual arrival date ($arrivalDateFormatted).',
      );
      return null;
    }

    shipment.pickupDateUtc = pickupDateUtc;
    // 如果状态是 "Arrived"，则更新为 "Picked Up"
    if (shipment.status == statusArrived) {
      shipment.status = statusPickedUp;
    }

    final success = await _storageService.updateShipment(shipment);
    if (success) {
      return shipment;
    } else {
      print(
        'Error: Failed to save shipment $trackingNumber pickup date update.',
      );
      return null;
    }
  }

  List<Shipment> getCurrentCustomerShipments() {
    if (_authService.currentRole == UserRole.customer &&
        _authService.currentCustomer != null) {
      _loggingService.info(
        'Customer "${_authService.currentCustomer!.customerCode}" listed their shipments.',
      );
      return _storageService.getShipmentsByCustomerCode(
        _authService.currentCustomer!.customerCode,
      );
    } else if (_authService.currentRole != UserRole.customer) {
      _loggingService.warning(
        'Permission denied: Attempt to list shipments by non-customer. Current role: ${_authService.currentRole}',
      );
      print(
        'Permission error: Only logged-in customers can query their own shipments.',
      );
      return [];
    } else {
      _loggingService.error(
        'Failed to list shipments: Current logged-in customer information is missing.',
      );
      print('Error: Current logged-in customer information is missing.');
      return [];
    }
  }

  Shipment? getShipmentDetailsForTrader(String trackingNumber) {
    final traderUsername =
        _authService.currentTraderUsername ?? "UnknownTrader";
    if (_authService.currentRole != UserRole.trader) {
      _loggingService.warning(
        'Permission denied: Attempt to view shipment details by non-trader. Current role: ${_authService.currentRole}',
      );
      print(
        'Permission error: Only traders can query arbitrary shipment details.',
      );
      return null;
    }
    final shipment = _storageService.getShipmentByTrackingNumber(
      trackingNumber,
    );
    if (shipment != null) {
      _loggingService.info(
        'Trader "$traderUsername" viewed details for shipment "$trackingNumber".',
      );
    } else {
      _loggingService.info(
        'Trader "$traderUsername" attempted to view details for non-existent shipment "$trackingNumber".',
      );
    }
    return shipment;
  }

  List<Shipment> getAllShipmentsForTrader() {
    final traderUsername =
        _authService.currentTraderUsername ?? "UnknownTrader";
    if (_authService.currentRole != UserRole.trader) {
      _loggingService.warning(
        'Permission denied: Attempt to list all shipments by non-trader. Current role: ${_authService.currentRole}',
      );
      print('Permission error: Only traders can retrieve all shipments.');
      return [];
    }
    _loggingService.info('Trader "$traderUsername" listed all shipments.');
    return _storageService.getAllShipments();
  }
}
